﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Linq.Expressions;
using WAU.DAL;
using WAU.DTOs.AppPermissionModule;
using WAU.Models;
using WAU.Models.AppUserModels;
using WAU.Models.Framework;
using WAU.Utils;

namespace WAU.Services
{
    public class AppPermissionService
    {
        private readonly EssentialDbContext dbContext;

        private readonly BaseRepoMysql<AppUser> repoUser;
        private readonly BaseRepoMysql<AppRole> repoRole;
        private readonly BaseRepoMysql<AppRoleMenuREL> repoRoleMenuREL;
        private readonly BaseRepoMysql<AppMenu> repoMenu;
        private readonly BaseRepoMysql<AppUserRoleREL> repoUserRoleREL;

        private readonly RepoMySql repoMySql = new RepoMySql();

        private readonly AppUserService appUserService;

        private readonly ILogger<AppPermissionService> logger;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="appUserService"></param>
        /// <param name="logger"></param>
        public AppPermissionService(EssentialDbContext dbContext, AppUserService appUserService,
            ILogger<AppPermissionService> logger)
        {
            this.dbContext = dbContext;

            repoUser = new BaseRepoMysql<AppUser>(dbContext);
            repoRole = new BaseRepoMysql<AppRole>(dbContext);
            repoRoleMenuREL = new BaseRepoMysql<AppRoleMenuREL>(dbContext);
            repoMenu = new BaseRepoMysql<AppMenu>(dbContext);
            repoUserRoleREL = new BaseRepoMysql<AppUserRoleREL>(dbContext);

            this.appUserService = appUserService;

            this.logger = logger;
        }

        #region 菜单

        /// <summary>
        /// 获取菜单页列表（不分页）
        /// </summary>
        /// <returns></returns>
        public async Task<List<AppMenuListItemSCO>> GetAppMenuList(ListAppMenuDto dto)
        {
            var menuList = await repoMenu.ListAsyncNoTracking(a => true);
            List<AppMenuListItemSCO> resultList = GatherAppMenuInLevel(menuList);
            if (string.IsNullOrEmpty(dto.MenuName))
            {
                return resultList;
            }
            else
            {
                return FilterAppMenuListByName(dto.MenuName, resultList);
            }            
        }

        /// <summary>
        /// 按名称筛选菜单（如果子项有匹配的，则父级也要显示）
        /// </summary>
        /// <param name="filterMenuName"></param>
        /// <param name="menuListItemSCOs"></param>
        /// <returns></returns>
        private List<AppMenuListItemSCO> FilterAppMenuListByName(string filterMenuName, IEnumerable<AppMenuListItemSCO> menuListItemSCOs)
        {
            List<AppMenuListItemSCO> filteredList = new List<AppMenuListItemSCO>();
            foreach(var item in menuListItemSCOs)
            {
                if (item.MenuName.Contains(filterMenuName))
                {
                    filteredList.Add(item);
                    continue;
                }

                if(item.Children == null)
                {
                    continue;
                }

                List<AppMenuListItemSCO> filteredChildren = FilterAppMenuListByName(filterMenuName, item.Children);
                if(filteredChildren.Count > 0)
                {
                    item.Children = filteredChildren.ToArray();
                    filteredList.Add(item);
                }
            }

            return filteredList;
        }

        /// <summary>
        /// AutoMapper 映射 AppMenu 和 AppMenuListItemSCO 的配置
        /// </summary>
        private static readonly MapperConfiguration _appMenuMapperConfig = new MapperConfiguration(cfg =>
        {
            IMappingExpression<AppMenu, AppMenuListItemSCO> exp = cfg.CreateMap<AppMenu, AppMenuListItemSCO>();
            exp.ForMember(a => a.Children, a => a.Ignore());
        });

        /// <summary>
        /// 按层级聚合 菜单
        /// </summary>
        /// <param name="appMenuList"></param>
        /// <returns></returns>
        private List<AppMenuListItemSCO> GatherAppMenuInLevel(List<AppMenu> appMenuList)
        {
            if (!appMenuList.Any())
            {
                return new List<AppMenuListItemSCO>();
            }

            // 按层级聚合
            var groupedData = appMenuList.OrderBy(a => a.Level).ThenBy(a => a.SortNum).ToList().GroupBy(a => a.Level);

            IMapper menuMapper = _appMenuMapperConfig.CreateMapper();

            // 向左 外连接关联，直到根节点
            int cursor = groupedData.Last().Key;
            List<AppMenuListItemSCO> resultList = groupedData.FirstOrDefault(a => a.Key == cursor)
                                                            .Select(a => menuMapper.Map<AppMenuListItemSCO>(a)).ToList();
            while (cursor > 1)
            {
                var upperLevelMenu = groupedData.FirstOrDefault(a => a.Key == cursor - 1)
                                        .Select(a => menuMapper.Map<AppMenuListItemSCO>(a));
                // GroupJoin 即为先聚合再关联
                resultList = upperLevelMenu.GroupJoin(resultList, a => a.Id, b => b.BelongId, (a, b) =>
                {
                    a.Children = b.Count() == 0 ? null : b.Select(c => c).ToArray();
                    return a;
                }).ToList();
                cursor--;
            }

            return resultList;
        }


        /// <summary>
        /// 获取菜单列表（供下拉选择时使用）
        /// </summary>
        /// <returns></returns>
        public async Task<List<AppMenu>> GetAppMenuListForSelect()
        {
            // 目前只支持最多二级菜单，因此只匹配层级为 1 的即可
            var menuList = await repoMenu.ListAsyncNoTracking(a => a.Level == 1);
            menuList = menuList.OrderBy(a => a.SortNum).ToList();
            return menuList;
        }

        /// <summary>
        /// 获取菜单详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ExecResult<AppMenu>> GetAppMenuDetail(string id)
        {
            AppMenu appMenu = await repoMenu.FindAsyncNoTracking(a => a.Id == id);
            if (appMenu == null)
            {
                return ExecResult<AppMenu>.Error("未找到对应的 菜单");
            }
            else
            {
                return ExecResult<AppMenu>.RetSuccess(appMenu);
            }
        }

        /// <summary>
        /// 编辑菜单
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <param name="appMenu"></param>
        /// <returns></returns>
        public async Task<ExecResult> EditAppMenu(string currentUserId, EditAppMenuDto appMenuDto)
        {
            if (string.IsNullOrEmpty(appMenuDto.BelongId))
            {
                appMenuDto.BelongId = null;
            }

            bool isAdd = string.IsNullOrEmpty(appMenuDto.Id);   // 添加还是编辑

            // 判断是否重复
            var existsQuery = repoMenu.QueryNoTracking(a => a.MenuName == appMenuDto.MenuName
                                                        || a.MenuPath == appMenuDto.MenuPath);

            if (isAdd)
            {
                if (existsQuery.Any())
                {
                    return ExecResult.Error("已经存在 名称 或 路径 相同的菜单");
                }

                AppMenu appMenu = new AppMenu();

                appMenu.Id = CommonUtils.GenerateShortUniqueId(8);
                appMenu.MenuName = appMenuDto.MenuName;
                appMenu.MenuPath = appMenuDto.MenuPath;
                appMenu.MenuIcon = appMenuDto.MenuIcon;
                appMenu.SortNum = appMenuDto.SortNum;
                appMenu.BelongId = appMenuDto.BelongId;

                if (!string.IsNullOrEmpty(appMenuDto.BelongId))
                {
                    AppMenu belongMenu = await repoMenu.FindAsyncNoTracking(a => a.Id == appMenuDto.BelongId);
                    if (belongMenu == null)
                    {
                        return ExecResult.Error("设置的父级菜单不存在");
                    }

                    appMenu.Level = belongMenu.Level + 1;
                }
                else
                {
                    appMenu.Level = 1;
                }

                appMenu.Creator = currentUserId;
                appMenu.CreateTime = DateTime.Now;

                repoMenu.Add(appMenu);
            }
            else
            {
                existsQuery = existsQuery.Where(a => a.Id != appMenuDto.Id);
                if (existsQuery.Any())
                {
                    return ExecResult.Error("已经存在 名称 或 路径 相同的菜单");
                }

                var entity = await repoMenu.FindAsync(appMenuDto.Id);
                if (entity == null)
                {
                    return ExecResult.Error("没有找到给定的菜单");
                }

                // 判断其是否存在子项
                var hasSubMenuQuery = repoMenu.QueryNoTracking(a => a.BelongId == entity.Id);
                if (hasSubMenuQuery.Any() &&
                    (appMenuDto.BelongId != entity.BelongId || appMenuDto.MenuName != entity.MenuName))
                {
                    return ExecResult.Error("当前菜单有子项，无法重新为其设置 层级 或 名称");
                }

                entity.MenuName = appMenuDto.MenuName;
                entity.MenuPath = appMenuDto.MenuPath;
                entity.MenuIcon = appMenuDto.MenuIcon;
                entity.SortNum = appMenuDto.SortNum;
                entity.BelongId = appMenuDto.BelongId;

                entity.Modifier = currentUserId;
                entity.ModifyTime = DateTime.Now;

                repoMenu.Update(entity);
            }

            await repoMenu.SaveChangesAsync();
            return ExecResult.ExecSuccessMsg(isAdd ? "添加成功" : "编辑成功");
        }

        /// <summary>
        /// 删除菜单（及其子项）
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ExecResult> DeleteAppMenu(string currentUserId, DeleteAppMenuDto dto)
        {
            // 1. 菜单数量不多，为避免多次请求数据库，一次全部查出
            List<AppMenu> allAppMenus = await repoMenu.ListAsync(a => true);
            List<AppMenu> toDelAppMenus = allAppMenus.Where(a => dto.Ids.Contains(a.Id)).ToList();

            List<AppMenu> toDelAppMenusWithSub = new List<AppMenu>();

            // 2. 逐个判断菜单是否有子集
            foreach (var toDelAppMenu in toDelAppMenus)
            {
                // 2.1 递归判断，并添加到待删除列表
                AddSubAppMenuToList(toDelAppMenu, allAppMenus, toDelAppMenusWithSub);
            }

            repoMenu.DeleteMany(currentUserId, toDelAppMenusWithSub);

            await repoMenu.SaveChangesAsync();
            return ExecResult.ExecSuccessMsg("删除成功");
        }

        /// <summary>
        /// 将 菜单的子项 添加到 指定列表
        /// </summary>
        /// <param name="appMenu"></param>
        /// <param name="allAppMenus"></param>
        /// <param name="targetMenuList"></param>
        private void AddSubAppMenuToList(AppMenu appMenu, List<AppMenu> allAppMenus, List<AppMenu> targetMenuList)
        {
            targetMenuList.Add(appMenu);

            List<AppMenu> subs = allAppMenus.Where(a => a.BelongId == appMenu.Id).ToList();
            foreach (var sub in subs)
            {
                AddSubAppMenuToList(sub, allAppMenus, targetMenuList);
            }
        }

        #endregion

        #region 角色

        /// <summary>
        /// 获取角色列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<List<AppRoleListItemSCO>> GetAppRoleList(ListAppRoleDto dto)
        {
            // 排除 默认角色
            var query = repoRole.QueryNoTracking(a => a.RoleCode != GlobalConfig.Setting.DefaultAppUserRoleCode);
            if (!string.IsNullOrEmpty(dto.RoleName))
            {
                query = query.Where(a => a.RoleName.Contains(dto.RoleName));
            }

            List<AppRole> dataList = await query.ToListAsync();
            List<AppRoleListItemSCO> resultList = dataList.OrderByDescending(a => a.CreateTime)
                                                    .Select(a => new AppRoleListItemSCO
                                                    {
                                                        Id = a.Id,
                                                        RoleName = a.RoleName,
                                                        RoleCode = a.RoleCode,
                                                        CreateTime = a.CreateTime
                                                    }).ToList();
            return resultList;
        }

        /// <summary>
        /// 获取角色详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ExecResult<AppRole>> GetAppRoleDetail(DetailAppRoleDto dto)
        {
            AppRole appRole = await repoRole.FindAsyncNoTracking(a => a.Id == dto.Id);
            if (appRole == null)
            {
                return ExecResult<AppRole>.Error("未找到对应的 角色");
            }
            else
            {
                return ExecResult<AppRole>.RetSuccess(appRole);
            }
        }

        /// <summary>
        /// 编辑角色
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ExecResult> EditAppRole(string currentUserId, EditAppRoleDto dto)
        {
            bool isAdd = string.IsNullOrEmpty(dto.Id);

            var existsQuery = repoRole.QueryNoTracking(a => a.RoleCode == dto.RoleCode || a.RoleName == dto.RoleName);

            if (isAdd)
            {
                if (existsQuery.Any())
                {
                    return ExecResult.Error("已经存在 code 或 名称相同的角色名");
                }

                AppRole appRole = new AppRole();

                appRole.Id = CommonUtils.GenerateShortUniqueId(8);
                appRole.RoleCode = dto.RoleCode;
                appRole.RoleName = dto.RoleName;
                appRole.Remark = dto.Remark;

                appRole.Creator = currentUserId;
                appRole.CreateTime = DateTime.Now;

                repoRole.Add(appRole);
            }
            else
            {
                existsQuery = existsQuery.Where(a => a.Id != dto.Id);
                if (existsQuery.Any())
                {
                    return ExecResult.Error("已经存在 code 或 名称相同的角色名");
                }

                var entity = await repoRole.FindAsync(dto.Id);
                if (entity == null)
                {
                    return ExecResult.Error("没有找到给定的角色");
                }

                entity.RoleCode = dto.RoleCode;
                entity.RoleName = dto.RoleName;
                entity.Remark = dto.Remark;

                entity.Modifier = currentUserId;
                entity.ModifyTime = DateTime.Now;

                repoRole.Update(entity);
            }

            await repoRole.SaveChangesAsync();
            return ExecResult.ExecSuccessMsg(isAdd ? "添加成功" : "编辑成功");
        }

        /// <summary>
        /// 删除角色
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ExecResult> DeleteAppRole(string currentUserId, DeleteAppRoleDto dto)
        {
            List<AppRole> toDelAppRole = repoRole.List(a => dto.Ids.Contains(a.Id));

            // 判断角色是否存在用户
            var hasUserQuery = repoUserRoleREL.QueryNoTracking(a => dto.Ids.Contains(a.RoleId));
            if (hasUserQuery.Any())
            {
                List<string> hasUserRoleIds = hasUserQuery.Select(a => a.RoleId).Distinct().ToList();
                return ExecResult.Error($"角色 {string.Join("，", hasUserRoleIds)}  存在关联用户");
            }

            repoRole.DeleteMany(currentUserId, toDelAppRole);

            await repoRole.SaveChangesAsync();
            return ExecResult.ExecSuccessMsg("删除成功");
        }

        #endregion

        #region 菜单 和 角色

        /// <summary>
        /// 获取某一角色的菜单
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<List<AppMenuListItemSCO>> GetRoleMenus(GetRoleMenusDto dto)
        {
            var menuQury = from menu in repoMenu.QueryNoTracking(a => true)
                           join roleMenu in repoRoleMenuREL.QueryNoTracking(a => true)
                               on menu.Id equals roleMenu.MenuId
                           where roleMenu.RoleId == dto.Id
                           select menu;

            List<AppMenu> resultList = await menuQury.ToListAsync();
            return GatherAppMenuInLevel(resultList);
        }

        /// <summary>
        /// 设置某一角色的菜单
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ExecResult> SetRoleMenus(string currentUserId, SetRoleMenusDto dto)
        {
            // 判断所选择的父级菜单是否都被选中
            List<AppMenu> targetAppMenuEntities = await repoMenu.ListAsyncNoTracking(a => dto.MenuIds.Contains(a.Id));
            foreach (var targetAppMenu in targetAppMenuEntities)
            {
                bool boolResult = IsMenuParentSelect(targetAppMenu, targetAppMenuEntities, out AppMenu notSelectParentMenu);
                if (!boolResult)
                {
                    return ExecResult.Error($"{notSelectParentMenu.MenuName} 未选择父级菜单");
                }
            }

            var targetRoleMenuRELs = dto.MenuIds.Select(a => new AppRoleMenuREL { MenuId = a, RoleId = dto.RoleId });
            var existingEntities = await repoRoleMenuREL.ListAsync(a => a.RoleId == dto.RoleId);

            // 分离出待添加项
            var toAddEntities = targetRoleMenuRELs.Except(existingEntities, RoleMenuRELEqualityComparer.Ins).ToList();
            foreach (var toAddEntity in toAddEntities)
            {
                toAddEntity.Id = GuidFactory.NewSortedGuid();
                toAddEntity.Creator = currentUserId;
            }
            repoRoleMenuREL.AddRange(toAddEntities);

            // 分离出待删除项
            var toDelEntities = existingEntities.Except(targetRoleMenuRELs, RoleMenuRELEqualityComparer.Ins).ToList();
            repoRoleMenuREL.DeleteMany(currentUserId, toDelEntities);

            await repoRoleMenuREL.SaveChangesAsync();
            return ExecResult.ExecSuccessMsg("设置角色菜单成功");
        }

        /// <summary>
        /// 判断菜单的父级是否都被选中（递归判断）
        /// </summary>
        /// <param name="currentAppMenu"></param>
        /// <param name="appMenus"></param>
        /// <param name="notSelectParentMenu"></param>
        /// <returns></returns>
        private bool IsMenuParentSelect(AppMenu currentAppMenu, List<AppMenu> appMenus, out AppMenu notSelectParentMenu)
        {
            notSelectParentMenu = null;

            // 1. 不需要有父级菜单，直接返回
            if (currentAppMenu.Level == 1)
            {
                return true;
            }

            // 2. 需要有父级菜单
            var parentAppMenu = appMenus.FirstOrDefault(a => a.Id == currentAppMenu.BelongId);
            // 2.1 没有父级菜单
            if (parentAppMenu == null)
            {
                notSelectParentMenu = currentAppMenu;
                return false;
            }
            else
            {
                // 2.2 继续判断其父级有没有父级菜单
                bool resultBool = IsMenuParentSelect(parentAppMenu, appMenus, out notSelectParentMenu);
                if (!resultBool)
                {
                    notSelectParentMenu = parentAppMenu;
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 用户权限 比较器（角色id 和 菜单id 相等则相等）
        /// </summary>
        private class RoleMenuRELEqualityComparer : IEqualityComparer<AppRoleMenuREL>
        {
            /// <summary>
            /// 私有 ctor
            /// </summary>
            private RoleMenuRELEqualityComparer() { }

            /// <summary>
            /// Ins
            /// </summary>
            public static RoleMenuRELEqualityComparer Ins = new RoleMenuRELEqualityComparer();

            public bool Equals(AppRoleMenuREL x, AppRoleMenuREL y)
            {
                return x.RoleId == y.RoleId && x.MenuId == x.MenuId;
            }

            public int GetHashCode(AppRoleMenuREL obj)
            {
                return HashCode.Combine(obj.RoleId, obj.MenuId);
            }
        }

        #endregion

        #region 权限

        /// <summary>
        /// 获取用户权限
        /// </summary>
        /// <param name="roleCodes"></param>
        /// <returns></returns>
        public async Task<List<AppMenuListItemSCO>> FetchUserPermission(List<string> roleCodes)
        {
            var roleMenuQuery = from role in repoRole.QueryNoTracking(a => roleCodes.Contains(a.RoleCode))
                                join roleMenu in repoRoleMenuREL.QueryNoTracking(a => true)
                                    on role.Id equals roleMenu.RoleId
                                join menu in repoMenu.QueryNoTracking(a => true)
                                    on roleMenu.MenuId equals menu.Id
                                select menu;
            List<AppMenu> appMenus = await roleMenuQuery.ToListAsync();
            return GatherAppMenuInLevel(appMenus);
        }

        /// <summary>
        /// 获取某一角色的用户列表
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="baseCondition"></param>
        /// <returns></returns>
        public async Task<QueryResult<AppUser>> GetRoleUserList(string roleId, BaseCondition baseCondition)
        {
            IQueryable<AppUser> finalQuery;
            QueryResult<AppUser> queryResult;

            if (!string.IsNullOrEmpty(roleId))
            {
                var userRoleQuery = repoUserRoleREL.QueryNoTracking(a => true).Where(a => a.RoleId == roleId);
                finalQuery = from userRole in userRoleQuery
                             join user in repoUser.QueryNoTracking(a => true)
                                on userRole.UserId equals user.Id
                             select user;
            }
            else
            {
                finalQuery = repoUser.QueryNoTracking(a => true);
            }

            if (!string.IsNullOrEmpty(baseCondition.SortField))
            {
                var ordering = CommonUtils.MakeOrderExpression<AppUser>(baseCondition.SortField);
                queryResult = await repoMySql.QueryResultByPageAsync(finalQuery, ordering, baseCondition, a => a.Id, true);
            }
            else
            {
                finalQuery = finalQuery.OrderByDescending(a => a.CreateTime);
                queryResult = await repoMySql.QueryResultByPageAsync(finalQuery, baseCondition);
            }

            return new QueryResult<AppUser>
            {
                DataList = queryResult.DataList,
                Total = queryResult.Total
            };
        }

        /// <summary>
        /// 获取用户角色
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<List<AppRole>> GetUserRoles(GetUserRolesDto dto)
        {
            var userRoleQuery = repoUserRoleREL.QueryNoTracking(a => a.UserId == dto.UserId);
            var query = from userRole in userRoleQuery
                        join role in repoRole.QueryNoTracking(a => true)
                            on userRole.RoleId equals role.Id
                        select role;

            return await query.ToListAsync();
        }

        /// <summary>
        /// 设置用户角色
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ExecResult> SetUserRoles(string currentUserId, SetUserRolesDto dto)
        {
            var targetUserRoleRELs = dto.RoleIds.Select(roleId => new AppUserRoleREL 
            { 
                UserId = dto.UserId, 
                RoleId = roleId
            }).ToList();
            var existingEntities = await repoUserRoleREL.ListAsync(a => a.UserId == dto.UserId);

            // 分离出待添加的项
            var toAddEntities = targetUserRoleRELs.Except(existingEntities, AppUserRoleRELEqualityComparer.Ins);
            foreach(var entity in toAddEntities)
            {
                entity.Id = GuidFactory.NewSortedGuid();

                entity.Creator = currentUserId;
                entity.CreateTime = DateTime.Now;

                repoUserRoleREL.Add(entity);
            }

            // 分离出待删除项
            var toDelEntities = existingEntities.Except(targetUserRoleRELs, AppUserRoleRELEqualityComparer.Ins);
            repoUserRoleREL.DeleteMany(currentUserId, toDelEntities);

            await repoUserRoleREL.SaveChangesAsync();
            return ExecResult.ExecSuccessMsg("设置用户角色成功");
        }

        /// <summary>
        /// 用户权限 比较器（角色id 和 菜单id 相等则相等）
        /// </summary>
        private class AppUserRoleRELEqualityComparer : IEqualityComparer<AppUserRoleREL>
        {
            /// <summary>
            /// 私有 ctor
            /// </summary>
            private AppUserRoleRELEqualityComparer() { }

            /// <summary>
            /// Ins
            /// </summary>
            public static AppUserRoleRELEqualityComparer Ins = new AppUserRoleRELEqualityComparer();

            public bool Equals(AppUserRoleREL x, AppUserRoleREL y)
            {
                return x.UserId == y.UserId && x.RoleId == x.RoleId;
            }

            public int GetHashCode(AppUserRoleREL obj)
            {
                return HashCode.Combine(obj.UserId, obj.RoleId);
            }
        }

        #endregion
    }
}
